home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2000 October
/
CHIP Turkiye Ekim 2000.iso
/
prog
/
naps
/
04
/
setup.exe
/
Gnucleus
/
ViewSearch.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2000-07-15
|
21KB
|
776 lines
/********************************************************************************
Gnucleus - A node application for the Gnutella network
Copyright (C) 2000 John Marshall
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For support, questions, comments, etc...
E-Mail:
swabby@c0re.net
Address:
21 Cadogan Way
Nashua, NH, USA 03062
********************************************************************************/
// ViewSearch.cpp : implementation file
//
#include "stdafx.h"
#include "Gnucleus.h"
#include "MainFrm.h"
#include "GnucleusDoc.h"
#include "ViewTransfer.h"
#include "ViewSearch.h"
#include "IPFilter.h"
#include "GnuTransfer.h"
#include "GnuHash.h"
#include "GnuSock.h"
#include "GnuControl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CViewSearch
IMPLEMENT_DYNCREATE(CViewSearch, CFormView)
CViewSearch::CViewSearch()
: CFormView(CViewSearch::IDD)
{
//{{AFX_DATA_INIT(CViewSearch)
//}}AFX_DATA_INIT
BytesPerSec = 0;
row = 0;
matches = 0;
}
CViewSearch::~CViewSearch()
{
}
void CViewSearch::DoDataExchange(CDataExchange* pDX)
{
CFormView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CViewSearch)
DDX_Control(pDX, IDC_BUTTON_DOWNLOAD, m_btnDownload);
DDX_Control(pDX, IDC_STATIC_MATCHES, m_stcMatches);
DDX_Control(pDX, IDC_STATIC_SUBSEARCH, m_stcSubsearch);
DDX_Control(pDX, IDC_STATIC_EXCLUDE, m_stcExclude);
DDX_Control(pDX, IDC_LIST_RESULTS, m_lstResults);
DDX_Control(pDX, IDC_EDIT_SUBSEARCH, m_eSubsearch);
DDX_Control(pDX, IDC_EDIT_EXCLUDE, m_eExclude);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CViewSearch, CFormView)
//{{AFX_MSG_MAP(CViewSearch)
ON_WM_SIZE()
ON_NOTIFY(NM_DBLCLK, IDC_LIST_RESULTS, OnDblclkListResults)
ON_BN_CLICKED(IDC_BUTTON_DOWNLOAD, OnButtonDownload)
ON_NOTIFY(NM_CLICK, IDC_LIST_RESULTS, OnClickListResults)
ON_NOTIFY(NM_RCLICK, IDC_LIST_RESULTS, OnRightClickListResults)
ON_NOTIFY(HDN_ITEMCLICK, IDC_LIST_RESULTS, OnItemclickListResults)
ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST_RESULTS, OnColumnclickListResults)
ON_EN_CHANGE(IDC_EDIT_SUBSEARCH, OnChangeSubsearch)
ON_EN_CHANGE(IDC_EDIT_EXCLUDE, OnChangeExclude)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CViewSearch diagnostics
#ifdef _DEBUG
void CViewSearch::AssertValid() const
{
CFormView::AssertValid();
}
void CViewSearch::Dump(CDumpContext& dc) const
{
CFormView::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CViewSearch message handlers
void CViewSearch::OnInitialUpdate()
// Initializes all the dialog controls on the local view
{
CFormView::OnInitialUpdate();
Doc = (CGnucleusDoc *) GetDocument();
Comm = Doc->GnuComm;
NoScroll = 0;
// Resize the window, set up the list box
int offSet;
if(m_lstResults.GetScrollLimit(SB_VERT))
offSet = ::GetSystemMetrics(SM_CXVSCROLL) + 3;
else
offSet = 4;
CRect rect;
m_lstResults.GetWindowRect(&rect);
m_lstResults.InsertColumn(0, "Name", LVCFMT_LEFT,
(rect.Width() - offSet) * 5/12, 0);
m_lstResults.InsertColumn(1, "Bytes", LVCFMT_RIGHT,
(rect.Width() - offSet) * 2/12, 1);
m_lstResults.InsertColumn(2, "Type", LVCFMT_LEFT,
(rect.Width() - offSet) * 2/12, 1);
m_lstResults.InsertColumn(3, "Node", LVCFMT_CENTER,
(rect.Width() - offSet) * 2/12, 0);
m_lstResults.InsertColumn(4, "Speed", LVCFMT_RIGHT,
(rect.Width() - offSet) * 1/12, 0);
m_lstResults.SetExtendedStyle(LVS_EX_FULLROWSELECT);
GetParentFrame()->GetClientRect(&rect);
OnSize(SIZE_RESTORED, rect.right - 4, rect.bottom - 4);
// Create and set the image list to store file icons
m_lstResults.SetImageList(GetSharedImageList(), LVSIL_SMALL);
// disable plain text sort with search items.
m_lstResults.EnableGenericSort(FALSE);
// Disable button
m_btnDownload.EnableWindow(FALSE);
// Get search value from title
CString Title;
GetParentFrame()->GetWindowText(Title);
length = Title.GetLength() - 16;
keyword = Title.Mid(15, length);
// Send a search query out for the keyword
CString strSpeed;
CComboBox *cbSpeed = (CComboBox *) ( (CMainFrame *) AfxGetApp()->m_pMainWnd )->GetDialogBar()->GetDlgItem(IDC_COMBO_SPEED);
cbSpeed->GetWindowText(strSpeed);
BytesPerSec = GetSpeedinBytes(strSpeed);
Send_Query();
}
WORD CViewSearch::GetSpeedinBytes(CString Speed)
// Speeds are in *bytes*/second
{
if(Speed == "")
return 0;
if(Speed == "14.4 Modem")
return 14;
if(Speed == "28.8 Modem")
return 29;
if(Speed == "56K Modem")
return 53;
if(Speed == "ISDN-56K")
return 56;
if(Speed == "ISDN-128K")
return 128;
if(Speed == "Cable")
return 384;
if(Speed == "DSL")
return 768;
if(Speed == "T1")
return 1500;
if(Speed == "T3 (or Greater)")
return 45000;
return (WORD) atof(Speed);
}
void CViewSearch::Send_Query()
// Build a query packet
{
GUID Guid = GUID_NULL;
::CoCreateGuid(&Guid);
if (Guid == GUID_NULL)
{
AfxMessageBox("Failed to create a GUID to send.");
return;
}
myGuid = Guid;
BYTE QueryByte[23 + 255];
packet_Query Query;
byte *pQuery = (byte *) &Query;
Query.Header.Guid = Guid;
Query.Header.Function = 0x80;
Query.Header.Hops = 0;
Query.Header.TTL = 7;
Query.Header.Payload = flipX( makeX(length + 3) );
Query.Speed = BytesPerSec;
for(int i = 0; i < 25; i++)
QueryByte[i] = pQuery[i];
// Add Search
for(i = 0; i < keyword.GetLength(); i++)
QueryByte[25 + i] = keyword.GetAt(i);
QueryByte[25 + length] = NULL;
// Insert GUID and broadcast the query
// Comm->m_cache[Guid] = NULL;
// Comm->HashTable.Insert(&Guid, NULL);
Comm->SendTable.Insert(&Guid, NULL);
Comm->Broadcast_Query((packet_Query *) QueryByte, 26 + length, NULL);
}
// move into position one of the controls at the bottom of the search window
void CViewSearch::AdjustBottomControl(CWnd *cntl, int bot)
{
CRect r, par;
cntl->GetWindowRect(&r);
ScreenToClient(&r);
const int hoff = 2, height = 32;
cntl->MoveWindow(r.left, (bot - hoff - height) + (height - r.Height()) / 2, r.Width(), r.Height());
}
void CViewSearch::OnSize(UINT nType, int cx, int cy)
// Adjusts dialog controls when window in resized
{
// Make sure dialog controls exist
if(m_lstResults.m_hWnd != NULL)
{
int top, left, btnLeft, btnRight, btnBottom;
// int btn2Left, btn2Right; // DW - not used yet?
RECT wndRect,
lstRect,
btnRect;
// btnRect2; // DW BTW, btnRect2 is not used for anything yet
GetWindowRect(&wndRect);
m_lstResults.GetWindowRect(&lstRect);
m_btnDownload.GetWindowRect(&btnRect);
top = lstRect.top - wndRect.top - 2;
left = lstRect.left - wndRect.left - 2;
btnLeft = btnRect.left - wndRect.left - 2;
btnRight = btnRect.right - btnRect.left;
btnBottom = btnRect.bottom - btnRect.top;
// btn2Left = btnRight + 8; // DW So, these are not valid yet
// btn2Right = btnRect2.right - btnRect2.left;
m_lstResults.MoveWindow(left, top, cx - left - 7, cy - top - btnBottom - 17);
m_btnDownload.MoveWindow(btnLeft, cy - 8 - btnBottom, btnRight, btnBottom);
AdjustBottomControl(&m_eSubsearch, cy);
AdjustBottomControl(&m_stcSubsearch, cy);
AdjustBottomControl(&m_stcExclude, cy);
AdjustBottomControl(&m_eExclude, cy);
// Resize list box
int offSet;
if(m_lstResults.GetScrollLimit(SB_VERT))
offSet = ::GetSystemMetrics(SM_CXVSCROLL) + 3;
else
offSet = 4;
CRect rect;
m_lstResults.GetWindowRect(&rect);
m_lstResults.SetColumnWidth(0, (rect.Width() - offSet) * 5/12);
m_lstResults.SetColumnWidth(1, (rect.Width() - offSet) * 2/12);
m_lstResults.SetColumnWidth(2, (rect.Width() - offSet) * 2/12);
m_lstResults.SetColumnWidth(3, (rect.Width() - offSet) * 2/12);
m_lstResults.SetColumnWidth(4, (rect.Width() - offSet) * 1/12);
}
CFormView::OnSize(nType, cx, cy);
}
void CViewSearch::UpdateResults(byte *Result)
{
if( ((packet_Header *) Result)->Guid != myGuid)
return;
DWORD length = makeD( flipX( ((packet_Header *) Result)->Payload)) + 23;
CString Node = IPtoStr( ((packet_QueryReply *) Result)->Host );
CString Port = WrdtoStr( ((packet_QueryReply *) Result)->Port );
CString Speed = DWrdtoStr( makeD( flipX( ((packet_QueryReply *) Result)->Speed)) );
CString File;
CString Size;
CString FileType;
byte hitsLeft = ((packet_QueryReply *) Result)->TotalHits;
DWORD nextPos = 34;
QueryItem Item;
GUID guid;
::memset (&guid, 0, sizeof (guid));
if (hitsLeft > 0)
{
// Extract the GUID from the end of the packet for push requests
DWORD guidStart = length - 16;
guid = * (GUID*) (Result + guidStart);
}
while(nextPos < length - 16 && hitsLeft > 0)
{
packet_QueryReplySet* ReplySet = (packet_QueryReplySet *) &Result[nextPos];
Size = DWrdtoStr( makeD( flipX( ReplySet->Size)) );
nextPos += 8;
while( !(Result[nextPos] == NULL && Result[nextPos + 1] == NULL))
if(nextPos > length - 16)
return;
else
File += Result[nextPos++];
if(Size == "0" || File == "")
return;
if( InspectFile(File) )
{
FileType = GetIconDesc(File);
// Add to listbox
// check if it passes subsearch
CString lowtxt = File;
lowtxt.MakeLower();
bool fnd; // represents whether passes subsearch and sub-excludes
if (subsearchText.GetLength() == 0)
fnd = true; // no subsearch
else
fnd = lowtxt.Find(subsearchText) >= 0;
Item.subsearchMatch = fnd;
// try excluding
Item.excluded = ExcludeTest(excludeText, lowtxt);
fnd = fnd && !Item.excluded;
if (fnd)
{
m_lstResults.InsertItem(row, "" );
m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Name" ), File);
m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Bytes" ), CommaIze(Size));
m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Type" ), FileType);
m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Node" ), Node);
m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Speed" ), Speed + " Kbs");
Item.Handle = row; // invalid, BTW
}
// Add to search results linked list
Item.Port = ((packet_QueryReply *) Result)->Port;
Item.Host = ((packet_QueryReply *) Result)->Host;
Item.Speed = makeD( flipX(((packet_QueryReply *) Result)->Speed));
Item.Index = makeD( flipX(ReplySet->Index));
Item.Size = makeD( flipX(ReplySet->Size));
// Remove directory information from the file name
int slash = File.ReverseFind('/');
File = File.Mid(slash + 1);
Item.FileName = File;
Item.FileType = FileType; // Ineffiecent, replace with list in future
Item.Guid = guid;
// Add the icon
Item.IconIndex = GetIconIndexFromName(File);
Replies.push_back (Item);
if(fnd && Item.IconIndex != -1)
{
m_lstResults.SetItem(row, 0, LVIF_IMAGE, NULL, Item.IconIndex, m_lstResults.GetColumnNumber( "Name" ), 0, NULL);
}
// Check to see if the scroll bar needs to be added
if( fnd && !NoScroll && m_lstResults.GetScrollLimit(SB_VERT))
{
CRect rect;
GetParentFrame()->GetClientRect(&rect);
OnSize(SIZE_RESTORED, rect.right - 4, rect.bottom - 4);
NoScroll = 1;
}
if (fnd)
row++;
matches++;
}
File = "";
Size = "";
nextPos += 2;
hitsLeft--;
}
AssignHeaderText();
}
bool CViewSearch::InspectFile(CString File)
{
bool Pass = 0;
File.MakeLower();
std::vector<BlockedSearch>::iterator it;
for( it = Doc->SearchFilter.begin(); it != Doc->SearchFilter.end(); it++)
{
if( (*it).Permis == 'A' )
if( SearchMatch( (*it).Name, File) )
Pass = 1;
if( (*it).Permis == 'D' )
if( SearchMatch( (*it).Name, File) )
return 0;
}
return Pass;
}
void CViewSearch::OnItemclickListResults(NMHDR* pNMHDR, LRESULT* pResult)
{
HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;
if(phdn->iButton == 0)
{
AfxMessageBox(m_lstResults.GetItemText(0, phdn->iItem));
}
*pResult = 0;
}
void CViewSearch::OnClickListResults(NMHDR* pNMHDR, LRESULT* pResult)
{
m_btnDownload.EnableWindow(m_lstResults.GetFirstSelectedItemPosition() != NULL);
*pResult = 0;
}
// pop up a popup menu, which right now lets one filter out a user
void CViewSearch::OnRightClickListResults(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMITEMACTIVATE Control = (LPNMITEMACTIVATE) pNMHDR;
int nItem = m_lstResults.HitTest(Control->ptAction);
if (nItem < 0 || nItem >= matches)
return;
CMenu menu;
VERIFY(menu.LoadMenu(IDR_SRCH_RCLICK));
CMenu *pmenuPopup = menu.GetSubMenu(0);
ASSERT(pmenuPopup != NULL);
// Display and track the popup menu
CPoint pos;
GetCursorPos(&pos);
int res = pmenuPopup->TrackPopupMenu( (TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_NONOTIFY|TPM_RETURNCMD),
pos.x, pos.y, this);
if (res == ID_FILTER) {
// they want to filter this user
// find out which result they clicked on
QueryItem& qry = FindQueryItemFromListIndex(nItem);
// now add the filter to our list
CIPFilter::AddFilter(CIPFilter::CIPAddress(qry.Host.a,qry.Host.b,qry.Host.c,qry.Host.d),
CIPFilter::CFilterItem::EFilterAction(CIPFilter::CFilterItem::eFilterDeny),
true); // true here necessary
// remove all the results from this loser that are currently displayed
IP host(qry.Host);
std::list<QueryItem>::iterator it;
for (it = Replies.begin(); it != Replies.end(); )
{
if (it->Host.S_addr == host.S_addr)
{
it = Replies.erase(it);
continue;
}
it++;
}
// redraw
ListFromReplies();
AssignHeaderText();
}
*pResult = 0;
}
void CViewSearch::OnDblclkListResults(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMITEMACTIVATE Control = (LPNMITEMACTIVATE) pNMHDR;
int nItem = m_lstResults.HitTest(Control->ptAction);
CString Title;
if(nItem != -1)
StartDownload(nItem);
*pResult = 0;
}
void CViewSearch::OnButtonDownload()
{
int nItem;
POSITION pos = m_lstResults.GetFirstSelectedItemPosition();
while(pos != NULL)
{
nItem = m_lstResults.GetNextSelectedItem(pos);
StartDownload(nItem);
}
}
void CViewSearch::OnColumnclickListResults(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
if (QueryItem::SortBy == pNMListView->iSubItem)
{
QueryItem::Reverse = !QueryItem::Reverse;
}
else
{
QueryItem::SortBy = pNMListView->iSubItem;
QueryItem::Reverse = 0;
}
Replies.sort ();
ListFromReplies();
*pResult = 0;
}
void CViewSearch::OnChangeSubsearch()
{
CString s;
m_eSubsearch.GetWindowText(s);
s.MakeLower();
subsearchText = s;
// see which replies match string
// keep track to see if we've made changes -- whether to reform list or not
bool madeAChange = false;
std::list<QueryItem>::iterator it;
for (it = Replies.begin(); it != Replies.end(); it++)
{
if (s.GetLength() == 0)
{
if (!it->subsearchMatch)
{
madeAChange = true;
it->subsearchMatch = true;
}
continue;
}
CString lo = it->FileName;
lo.MakeLower();
bool oldMatch = it->subsearchMatch;
bool fnd = SearchMatch("*" + s + "*", lo);
it->subsearchMatch = fnd;
if (it->subsearchMatch != oldMatch)
madeAChange = true;
}
if (madeAChange)
{
Replies.sort();
ListFromReplies();
AssignHeaderText();
}
}
// Test name against comma delimited excludes, return true if one matches
bool CViewSearch::ExcludeTest(CString exclude, CString name)
{
if (exclude.GetLength() == 0)
return false;
name.MakeLower();
exclude.MakeLower();
// parse exclude out
CString strSub;
int iToken = 0;
while(AfxExtractSubString(strSub, exclude, iToken, ','))
{
iToken++;
if(SearchMatch("*" + strSub + "*", name))
{
return true;
}
}
return false;
}
void CViewSearch::OnChangeExclude()
{
CString s;
m_eExclude.GetWindowText(s);
s.MakeLower();
excludeText = s;
// see which replies match exclude string -- they're invalid
// keep track to see if we've made changes -- whether to reform list or not
bool madeAChange = false;
std::list<QueryItem>::iterator it;
for (it = Replies.begin(); it != Replies.end(); it++)
{
if (s.GetLength() == 0)
{
if (it->excluded)
{
madeAChange = true;
it->excluded = false;
}
continue;
}
bool match = ExcludeTest(s, it->FileName);
bool oldMatch = it->excluded;
it->excluded = match;
if (match != oldMatch)
madeAChange = true;
}
if (madeAChange)
{
Replies.sort();
ListFromReplies();
AssignHeaderText();
}
}
/*
take our reply list and create the elements of the listcontrol from it
also count rows, as we might have just done some subsearch
*/
void CViewSearch::ListFromReplies()
{
m_lstResults.SetRedraw (FALSE);
m_lstResults.DeleteAllItems();
std::list<QueryItem>::iterator it;
row = 0;
for (it = Replies.begin(); it != Replies.end(); it++)
{
if (!it->subsearchMatch || it->excluded)
continue;
// Add to listbox
m_lstResults.InsertItem(row, "");
m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Name" ), (*it).FileName);
m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Bytes" ), CommaIze(DWrdtoStr((*it).Size)));
m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Type" ), (*it).FileType);
m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Node" ), IPtoStr((*it).Host));
m_lstResults.SetItemText(row, m_lstResults.GetColumnNumber( "Speed" ), DWrdtoStr((*it).Speed) + " Kbs");
if ((*it).IconIndex != -1)
{
m_lstResults.SetItem(row, 0, LVIF_IMAGE, NULL, (*it).IconIndex, m_lstResults.GetColumnNumber( "Name" ), 0, NULL);
}
row++;
}
m_lstResults.SetRedraw();
}
// set the header text -- how many matches so far
void CViewSearch::AssignHeaderText()
{
CString Title = WrdtoStr(matches);
Title += " Matches";
// maybe there's a subsearch -- if so, add text
if (matches != row)
Title += " (" + WrdtoStr(row) + " shown)";
m_stcMatches.SetWindowText(Title);
}
QueryItem& CViewSearch::FindQueryItemFromListIndex(int nItem)
{
ASSERT (nItem >= 0);
ASSERT (nItem < Replies.size ());
std::list <QueryItem>::iterator it;
it = Replies.begin();
// find the associated reply
while ( (it != Replies.end()) && (!it->subsearchMatch || it->excluded) )
it++;
for (int loop = 0; loop < nItem && (it != Replies.end()); ++loop)
{
do {
it++;
} while ( (it != Replies.end()) && (!it->subsearchMatch || it->excluded) );
}
ASSERT (it != Replies.end ());
return *it;
}
void CViewSearch::StartDownload(int nItem)
{
((CGnucleusApp *) AfxGetApp())->TransferFrame->ShowWindow(SW_SHOW);
((CGnucleusApp *) AfxGetApp())->TransferFrame->BringWindowToTop();
QueryItem& qry = FindQueryItemFromListIndex(nItem);
int b_is_dest_private_ip = CIPFilter::IsPrivateIP( qry.Host, StrtoIP(Comm->localHost) );
if( b_is_dest_private_ip == 0x2)
Comm->NewPushRequest(qry); // the remote download is not on the local subnet, push is the only way
else if( b_is_dest_private_ip == 0x4)
return; // we are on a different private IP address space. There is no way of download.
// TODO: generate an error message
else
// the destination is either on an open IP space, or it might be on our local address space, if not a push is generated.
((CViewTransfer *) ((CGnucleusApp *) AfxGetApp())->TransferFrame->GetActiveView())->NewDownload(qry);
}